package net.k3rnel.abugadro.providers;

import java.io.File;
import java.util.HashMap;

import net.k3rnel.abugadro.gcodes.Comment.Comments;
import net.k3rnel.abugadro.gcodes.CommentUpdate.CommentUpdates;
import net.k3rnel.abugadro.gcodes.Issue.Issues;
import net.k3rnel.abugadro.gcodes.Label.Labels;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;

public class ExternalContentProvider extends ContentProvider {

	private static final String DATABASE_NAME = "abuga.db";
	private static final String EXT_PATH = Environment.getExternalStorageDirectory()+"/data/net.k3rnel.abugadro/";
	private static final int DATABASE_VERSION = 3;
	private static final String PROJECTS_TABLE_NAME = "projects";
	private static final String ISSUES_TABLE_NAME = "issues";
	private static final String LABELS_TABLE_NAME = "labels";
	private static final String COMMENTS_TABLE_NAME = "comments";
	private static final String COMMENTUPDATES_TABLE_NAME = "commentupdates";
	public static final String AUTHORITY = "net.k3rnel.abugadro.external";

	private static final UriMatcher sUriMatcher;

	private static final int ISSUES = 3;
	private static final int ISSUE = 4;
	private static final int LABELS = 5;
	private static final int LABEL = 6;
	private static final int COMMENTS = 7;
	private static final int COMMENT = 8;
	private static final int COMMENTUPDATES = 9;
	private static final int COMMENTUPDATE = 10;

	private static HashMap<String, String> issuesProjectionMap;
	private static HashMap<String, String> labelsProjectionMap;
	private static HashMap<String, String> commentsProjectionMap;
	private static HashMap<String, String> commentUpdatesProjectionMap;

	static class DatabaseHelper{
		private SQLiteDatabase db;
		final Context mCtx;

		private DatabaseHelper(Context context) {
			mCtx = context;
		}

		public void open() {
			File dbFile=null;
			if (/*Settings.DoSDDB() && */Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
				new File(EXT_PATH).mkdirs();
				dbFile = new File(EXT_PATH, DATABASE_NAME);
			}
			else
				dbFile = mCtx.getDatabasePath(DATABASE_NAME);

			if (dbFile.exists()) {
				Log.i("SQLiteHelper", "Opening database at "+dbFile);
				db = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
				if (DATABASE_VERSION > db.getVersion())
					onUpgrade(db.getVersion());
			}
			else {
				Log.i("SQLiteHelper", "Creating database at "+dbFile);
				db = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
				onCreate();
			}         
		}

		public void close() {
			db.close();
		}

		public void onCreate() {
			db.execSQL("CREATE TABLE " + ISSUES_TABLE_NAME + " ("
					+ Issues._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ Issues.PROJECT_ID + " INTEGER ,"
					+ Issues.ISSUE_ID + " INTEGER ,"
					+ Issues.PUBLISHED + " TIMESTAMP DATE ,"
					+ Issues.UPDATED + " TIMESTAMP DATE ,"
					+ Issues.TITLE + " TEXT ,"
					+ Issues.CONTENT + " TEXT ,"
					+ Issues.AUTHOR + " TEXT ,"
					+ Issues.OWNER + " TEXT ,"
					+ Issues.STARS + " INTEGER ,"
					+ Issues.STATE + " TEXT ,"
					+ Issues.STATUS + " TEXT "
					+")");
			db.execSQL("CREATE TABLE " + LABELS_TABLE_NAME + " ("
					+ Labels._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ Labels.ISSUE_ID + " INTEGER ,"
					+ Labels.PROJECT_ID + " INTEGER ,"
					+ Labels.LABEL + " TEXT "
					+")");
			db.execSQL("CREATE TABLE " + COMMENTS_TABLE_NAME + " ("
					+ Comments._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ Comments.PROJECT_ID + " INTEGER ,"
					+ Comments.ISSUE_ID + " INTEGER ,"
					+ Comments.COMMENT_ID + " INTEGER ,"
					+ Comments.PUBLISHED + " TIMESTAMP DATE ,"
					+ Comments.UPDATED + " TIMESTAMP DATE ,"
					+ Comments.TITLE + " TEXT, "
					+ Comments.AUTHOR + " TEXT, "
					+ Comments.CONTENT + " TEXT "
					+")");
			db.execSQL("CREATE TABLE " + COMMENTUPDATES_TABLE_NAME + " ("
					+ CommentUpdates._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ CommentUpdates.ISSUE_ID + " INTEGER ,"
					+ CommentUpdates.PROJECT_ID + " INTEGER ,"
					+ CommentUpdates.COMMENT_ID + " INTEGER ,"
					+ CommentUpdates.CONTENT + " TEXT ,"
					+ CommentUpdates.TYPE + " TEXT ,"
					+ CommentUpdates.POSITIVE + " INTEGER "
					+")");
			db.setVersion(DATABASE_VERSION);

		}

		public void onUpgrade(int version) {
			while(version < DATABASE_VERSION){
				version++;
				switch(version){
				case 2:
					db.execSQL("ALTER TABLE "+ISSUES_TABLE_NAME+" ADD "+Issues.OWNER+" TEXT");
					db.setVersion(version);
					break;
				case 3:
					db.execSQL("ALTER TABLE "+COMMENTUPDATES_TABLE_NAME+" ADD "+CommentUpdates.TYPE+" TEXT");
					db.setVersion(version);
					break;
				}
			}
			 
				
		}

		public SQLiteDatabase getWritableDatabase() {
			if (db==null)
				open();
			return db;
		}
	}
	
	private DatabaseHelper dbHelper;
	
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int count;
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		switch (sUriMatcher.match(uri)) {
		case ISSUES:
			count = db.delete(ISSUES_TABLE_NAME, selection, selectionArgs);
			break;
		case ISSUE:
			count = db.delete(ISSUES_TABLE_NAME, Issues._ID + " = " + uri.getPathSegments().get(2), selectionArgs);			
			break;
		case LABELS:
			count = db.delete(LABELS_TABLE_NAME, selection, selectionArgs);
			break;
		case LABEL:
			count = db.delete(LABELS_TABLE_NAME, Labels._ID + " = " + uri.getPathSegments().get(2), selectionArgs);			
			break;
		case COMMENTS:
			count = db.delete(COMMENTS_TABLE_NAME, selection, selectionArgs);
			break;
		case COMMENT:
			count = db.delete(COMMENTS_TABLE_NAME, Comments._ID + " = " + uri.getPathSegments().get(2), selectionArgs);			
			break;
		case COMMENTUPDATES:
			count = db.delete(COMMENTUPDATES_TABLE_NAME, selection, selectionArgs);
			break;
		case COMMENTUPDATE:
			count = db.delete(COMMENTUPDATES_TABLE_NAME, CommentUpdates._ID + " = " + uri.getPathSegments().get(2), selectionArgs);			
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		dbHelper.mCtx.getContentResolver().notifyChange(uri, null);
		//		db.close();
		return count;
	}

	public String getType(Uri uri) {
		switch (sUriMatcher.match(uri)) {
		case ISSUES:
			return Issues.CONTENT_TYPE_DIR;
		case ISSUE:
			return Issues.CONTENT_TYPE_ITEM;
		case LABELS:
			return Labels.CONTENT_TYPE_DIR;
		case LABEL:
			return Labels.CONTENT_TYPE_ITEM;
		case COMMENTS:
			return Comments.CONTENT_TYPE_DIR;
		case COMMENT:
			return Comments.CONTENT_TYPE_ITEM;
		case COMMENTUPDATES:
			return CommentUpdates.CONTENT_TYPE_DIR;
		case COMMENTUPDATE:
			return CommentUpdates.CONTENT_TYPE_ITEM;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}

	public Uri insert(Uri uri, ContentValues values) {
		final int match = sUriMatcher.match(uri);
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		switch (match) {
		case ISSUES:{
			db.insertOrThrow(ISSUES_TABLE_NAME,"",values);
			return Issues.buildUri(values.getAsString(Issues.PROJECT_ID),values.getAsString(Issues._ID));
		}
		case LABELS:{
			db.insertOrThrow(LABELS_TABLE_NAME,"",values);
			return Labels.buildUri(values.getAsString(Labels._ID));
		}
		case COMMENTS:{
			db.insertOrThrow(COMMENTS_TABLE_NAME,"",values);
			return Labels.buildUri(values.getAsString(Comments._ID));
		}
		case COMMENTUPDATES:{
			db.insertOrThrow(COMMENTUPDATES_TABLE_NAME,"",values);
			return Labels.buildUri(values.getAsString(CommentUpdates._ID));
		}default: {
			throw new UnsupportedOperationException("Unknown uri: " + uri);
		}
		}

	}
	
	@Override
	public boolean onCreate() {
		dbHelper = new DatabaseHelper(getContext());
		return true;
	}
	
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		switch (sUriMatcher.match(uri)) {
		case ISSUES:
			qb.setTables(ISSUES_TABLE_NAME);
			qb.setProjectionMap(issuesProjectionMap);
			break;
		case ISSUE:
			qb.setTables(ISSUES_TABLE_NAME);
			qb.setProjectionMap(issuesProjectionMap);
			qb.appendWhere(Issues.PROJECT_ID + " = " + uri.getPathSegments().get(1)+ 
					" AND "+Issues.ISSUE_ID +" = "+uri.getPathSegments().get(3));   
			break;
		case LABELS:
			qb.setTables(LABELS_TABLE_NAME);
			qb.setProjectionMap(labelsProjectionMap);
			break;
		case LABEL:
			qb.setTables(LABELS_TABLE_NAME);
			qb.setProjectionMap(labelsProjectionMap);
			qb.appendWhere(Labels.PROJECT_ID + " = " + uri.getPathSegments().get(1) +
					" AND "+Labels.ISSUE_ID + " = " +uri.getPathSegments().get(3));   
			break;
		case COMMENTS:
			qb.setTables(COMMENTS_TABLE_NAME);
			qb.setProjectionMap(commentsProjectionMap);
			break;
		case COMMENT:
			qb.setTables(COMMENTS_TABLE_NAME);
			qb.setProjectionMap(commentsProjectionMap);
			qb.appendWhere(Comments._ID + " = " + uri.getPathSegments().get(3));   
			break;
		case COMMENTUPDATES:
			qb.setTables(COMMENTUPDATES_TABLE_NAME);
			qb.setProjectionMap(commentUpdatesProjectionMap);
			break;
		case COMMENTUPDATE:
			qb.setTables(COMMENTUPDATES_TABLE_NAME);
			qb.setProjectionMap(commentUpdatesProjectionMap);
			qb.appendWhere(CommentUpdates._ID + " = " + uri.getPathSegments().get(5));   
			break;
		default:
			throw new IllegalArgumentException("Unknown URI on Query: " + uri);
		}

		SQLiteDatabase db = dbHelper.getWritableDatabase();
		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);

		c.setNotificationUri(dbHelper.mCtx.getContentResolver(), uri);
		return c;
	}

	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		int count;
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		switch (sUriMatcher.match(uri)) {
		case ISSUES:
			count = db.update(ISSUES_TABLE_NAME, values, selection, selectionArgs);
			break;
		case LABELS:
			count = db.update(LABELS_TABLE_NAME, values, selection, selectionArgs);
			break;
		case COMMENTS:
			count = db.update(COMMENTS_TABLE_NAME, values, selection, selectionArgs);
			break;
		case COMMENTUPDATES:
			count = db.update(COMMENTUPDATES_TABLE_NAME, values, selection, selectionArgs);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI on Update " + uri);
		}
		dbHelper.mCtx.getContentResolver().notifyChange(uri, null);
		return count;

	}
	static {
		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		sUriMatcher.addURI(AUTHORITY, PROJECTS_TABLE_NAME+"/*/"+ISSUES_TABLE_NAME, ISSUES);
		sUriMatcher.addURI(AUTHORITY, PROJECTS_TABLE_NAME+"/*/"+ISSUES_TABLE_NAME+"/*/"+LABELS_TABLE_NAME, LABELS); 
		sUriMatcher.addURI(AUTHORITY, PROJECTS_TABLE_NAME+"/*/"+ISSUES_TABLE_NAME+"/*/"+LABELS_TABLE_NAME+"/*", LABEL);
		sUriMatcher.addURI(AUTHORITY, PROJECTS_TABLE_NAME+"/*/"+ISSUES_TABLE_NAME+"/*/"+COMMENTS_TABLE_NAME, COMMENTS);
		sUriMatcher.addURI(AUTHORITY, PROJECTS_TABLE_NAME+"/*/"+ISSUES_TABLE_NAME+"/*/"+COMMENTS_TABLE_NAME+"/*/"+COMMENTUPDATES_TABLE_NAME, COMMENTUPDATES);
		sUriMatcher.addURI(AUTHORITY, PROJECTS_TABLE_NAME+"/*/"+ISSUES_TABLE_NAME+"/*/"+COMMENTS_TABLE_NAME+"/*/"+COMMENTUPDATES_TABLE_NAME+"/*", COMMENTUPDATE);

		sUriMatcher.addURI(AUTHORITY, PROJECTS_TABLE_NAME+"/*/"+ISSUES_TABLE_NAME+"/*/"+COMMENTS_TABLE_NAME+"/*", COMMENT);
		sUriMatcher.addURI(AUTHORITY, PROJECTS_TABLE_NAME+"/*/"+ISSUES_TABLE_NAME+"/*", ISSUE);

		issuesProjectionMap = new HashMap<String, String>();
		issuesProjectionMap.put(Issues._ID, Issues._ID);
		issuesProjectionMap.put(Issues.PROJECT_ID, Issues.PROJECT_ID);
		issuesProjectionMap.put(Issues.ISSUE_ID, Issues.ISSUE_ID);
		issuesProjectionMap.put(Issues.PUBLISHED, Issues.PUBLISHED);
		issuesProjectionMap.put(Issues.UPDATED, Issues.UPDATED);
		issuesProjectionMap.put(Issues.TITLE, Issues.TITLE);
		issuesProjectionMap.put(Issues.CONTENT, Issues.CONTENT);
		issuesProjectionMap.put(Issues.AUTHOR, Issues.AUTHOR);
		issuesProjectionMap.put(Issues.OWNER, Issues.OWNER);
		issuesProjectionMap.put(Issues.STARS, Issues.STARS);
		issuesProjectionMap.put(Issues.STATE, Issues.STATE);
		issuesProjectionMap.put(Issues.STATUS, Issues.STATUS);

		labelsProjectionMap = new HashMap<String, String>();
		labelsProjectionMap.put(Labels._ID, Labels._ID);
		labelsProjectionMap.put(Labels.ISSUE_ID, Labels.ISSUE_ID);
		labelsProjectionMap.put(Labels.PROJECT_ID, Labels.PROJECT_ID);
		labelsProjectionMap.put(Labels.LABEL, Labels.LABEL);

		commentsProjectionMap = new HashMap<String, String>();
		commentsProjectionMap.put(Comments._ID, Comments._ID);
		commentsProjectionMap.put(Comments.PROJECT_ID, Comments.PROJECT_ID);
		commentsProjectionMap.put(Comments.ISSUE_ID, Comments.ISSUE_ID);
		commentsProjectionMap.put(Comments.COMMENT_ID, Comments.COMMENT_ID);
		commentsProjectionMap.put(Comments.PUBLISHED, Comments.PUBLISHED);
		commentsProjectionMap.put(Comments.UPDATED, Comments.UPDATED);
		commentsProjectionMap.put(Comments.AUTHOR, Comments.AUTHOR);
		commentsProjectionMap.put(Comments.TITLE, Comments.TITLE);
		commentsProjectionMap.put(Comments.CONTENT, Comments.CONTENT);

		commentUpdatesProjectionMap = new HashMap<String, String>();
		commentUpdatesProjectionMap.put(CommentUpdates._ID, CommentUpdates._ID);
		commentUpdatesProjectionMap.put(CommentUpdates.PROJECT_ID, CommentUpdates.PROJECT_ID);
		commentUpdatesProjectionMap.put(CommentUpdates.ISSUE_ID, CommentUpdates.ISSUE_ID);
		commentUpdatesProjectionMap.put(CommentUpdates.COMMENT_ID, CommentUpdates.COMMENT_ID);
		commentUpdatesProjectionMap.put(CommentUpdates.CONTENT, CommentUpdates.CONTENT);
		commentUpdatesProjectionMap.put(CommentUpdates.TYPE, CommentUpdates.TYPE);
		commentUpdatesProjectionMap.put(CommentUpdates.POSITIVE, CommentUpdates.POSITIVE);
	}

	public static long getId(Uri uri) {
		return ContentUris.parseId(uri);
	}
}
